﻿namespace GitUI;

/// <summary>
/// Sets the mouse cursor to <see cref="Cursors.WaitCursor"/> to indicate UI activity over some lexical scope.
/// </summary>
/// <remarks>
/// Usage is:
/// <code>
/// using (WaitCursorScope.Enter())
/// {
///     // perform UI activity
/// }
/// </code>
/// This pattern ensures:
/// <list type="bullet">
/// <item>The cursor is always restored when the block exits, whether by fall-through, return or exception.</item>
/// <item>Nested scopes work properly. That is, an inner scope doesn't reset the mouse when it exits.
/// Only the top-most scope will fully restore the mouse cursor.</item>
/// </list>
/// </remarks>
public readonly struct WaitCursorScope : IDisposable
{
    /// <summary>
    /// Starts a new scope, recording <see cref="Cursor.Current"/> and setting the mouse cursor to <see cref="Cursors.WaitCursor"/>.
    /// </summary>
    public static WaitCursorScope Enter(Cursor? cursor = null)
    {
        Cursor cursorAtStartOfScope = Cursor.Current;

        Cursor.Current = cursor ?? Cursors.WaitCursor;

        return new WaitCursorScope(cursorAtStartOfScope);
    }

    private readonly Cursor _cursorAtStartOfScope;

    private WaitCursorScope(Cursor cursorAtStartOfScope)
    {
        _cursorAtStartOfScope = cursorAtStartOfScope;
    }

    /// <summary>
    /// Restores <see cref="Cursor.Current"/> to the value captured in the constructor.
    /// </summary>
    public void Dispose()
    {
        Cursor.Current = _cursorAtStartOfScope;
    }
}
